# -*- coding: utf-8 -*-
"""
JPG照片传感器坏点和镜头脏污检测工具 - GUI界面
功能：
1. 选择图片文件
2. 显示检测结果
3. 对热点和死点进行画圈标记
4. 根据检测结果自动判断是否通过
"""
import os
import sys
import tkinter as tk
from tkinter import filedialog, messagebox, ttk
from PIL import Image, ImageTk, ImageDraw
import numpy as np
from datetime import datetime
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import ctypes
# 导入检测类
from detect_photo_issues import PhotoIssueDetector

# 启用高DPI支持
if sys.platform == 'win32':
    ctypes.windll.shcore.SetProcessDpiAwareness(1)

def get_scaling_factor():
    """获取系统缩放因子"""
    if sys.platform == 'win32':
        try:
            return ctypes.windll.user32.GetDpiForSystem() / 96
        except:
            return 1.0
    else:
        # 其他平台默认缩放因子为1.0
        return 1.0

# 获取缩放因子
scaling_factor = get_scaling_factor()
class PhotoDetectorGUI:
    def __init__(self, root):
        self.root = root
        
        # 设置窗口标题，移除默认图标
        self.root.title("cannice - 照片传感器坏点和镜头脏污检测工具V0.0.2")
        # 移除窗口图标
        self.root.iconbitmap(default='')
        # 对于Windows系统，额外设置空图标（使用try-except避免潜在错误）
        if sys.platform == 'win32':
            try:
                # 创建一个1x1的透明图标
                icon = tk.PhotoImage(width=1, height=1)
                self.root.iconphoto(False, icon)
                # 保持引用避免垃圾回收
                self._icon = icon
            except Exception as e:
                pass
        
        # 调整窗口大小，增大宽度和高度以适应更大的图像显示
        width = int(500 * scaling_factor)
        height = int(600 * scaling_factor)
        self.root.geometry(f"{width}x{height}")
        self.root.resizable(True, True)
        
        # 设置中文字体支持，添加更多备选字体提高兼容性
        plt.rcParams["font.family"] = ["SimHei", "WenQuanYi Micro Hei", "Heiti TC", "Microsoft YaHei", "Arial Unicode MS", "sans-serif"]
        
        # 设置Matplotlib的DPI和字体大小
        plt.rcParams['figure.dpi'] = 100 * scaling_factor
        plt.rcParams['font.size'] = 10 * scaling_factor
        
        # 初始化检测器 (与detect_photo_issues.py同步参数)
        self.detector = PhotoIssueDetector(sensitivity=2.5, blur_threshold=80, dirty_threshold=0.1)
        
        # 图像路径
        self.image_path = None
        self.result_img = None
        
        # 创建界面
        self.create_widgets()
    
    def create_widgets(self):
        # 创建主框架
        main_frame = ttk.Frame(self.root, padding="10")
        main_frame.pack(fill=tk.BOTH, expand=True)

        # 仅在窗口标题中显示cannice，不添加额外标签

        # 顶部控制区
        control_frame = ttk.Frame(main_frame)
        control_frame.pack(fill=tk.X, pady=(10, 10))
        
        # 选择图片按钮
        btn_font_size = int(10 * scaling_factor)
        self.select_btn = ttk.Button(control_frame, text="选择图片", command=self.select_image, style='Custom.TButton')
        self.select_btn.pack(side=tk.LEFT, padx=5)
        
        # 检测按钮
        self.detect_btn = ttk.Button(control_frame, text="开始检测", command=self.start_detection, state=tk.DISABLED, style='Custom.TButton')
        self.detect_btn.pack(side=tk.LEFT, padx=5)
        
        # 创建自定义按钮样式
        style = ttk.Style()
        style.configure('Custom.TButton', font=('SimHei', btn_font_size))
        
        # 图像路径显示
        self.path_var = tk.StringVar()
        path_entry = ttk.Entry(control_frame, textvariable=self.path_var, width=int(40 * scaling_factor))
        path_entry.pack(side=tk.LEFT, padx=5, fill=tk.X, expand=True)
        
        # 分割线
        ttk.Separator(main_frame).pack(fill=tk.X, pady=5)
        
        # 中间图像显示区
        image_frame = ttk.LabelFrame(main_frame, text="图像预览", padding="10")
        # 进一步限制图像区域，为结果区域提供更多空间
        image_frame.pack(fill=tk.BOTH, expand=False, pady=(0, 5))
        
        # 增大图形尺寸以提高图片显示质量
        fig_width = 4 * scaling_factor
        fig_height = 2 * scaling_factor
        self.fig, self.ax = plt.subplots(figsize=(fig_width, fig_height), dpi=100)
        self.ax.axis('off')
        self.ax.set_title("请选择一张图片")
        self.canvas = FigureCanvasTkAgg(self.fig, master=image_frame)
        self.canvas.draw()
        self.canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True)
        
        # 分割线
        ttk.Separator(main_frame).pack(fill=tk.X, pady=5)
        
        # 底部结果显示区
        result_frame = ttk.LabelFrame(main_frame, text="检测结果", padding="10")
        result_frame.pack(fill=tk.BOTH, expand=True)
        
        # 增加表格高度，显示更多检测结果
        self.result_tree = ttk.Treeview(result_frame, columns=('项目', '数值'), show='headings', height=6)
        self.result_tree.heading('项目', text='检测项目')
        self.result_tree.heading('数值', text='检测结果')
        self.result_tree.column('项目', width=int(120 * scaling_factor), anchor=tk.CENTER)
        self.result_tree.column('数值', width=int(150 * scaling_factor), anchor=tk.CENTER)
        self.result_tree.pack(fill=tk.X, pady=5)
        
        # 结果判定
        self.judge_var = tk.StringVar()
        self.judge_var.set("等待检测...")
        # 增大字体大小并设置自动换行
        font_size = int(11 * scaling_factor)
        self.judge_label = ttk.Label(result_frame, textvariable=self.judge_var, font=('SimHei', font_size, 'bold'), wraplength=450 * scaling_factor)
        # 增加填充并确保标签充分扩展
        self.judge_label.pack(pady=10, padx=5, fill=tk.BOTH, expand=True)
    
    def select_image(self):
        """选择图片文件"""
        file_types = [('JPG文件', '*.jpg'), ('所有文件', '*.*')]
        self.image_path = filedialog.askopenfilename(title="选择图片", filetypes=file_types)
        
        if self.image_path:
            self.path_var.set(self.image_path)
            self.detect_btn.config(state=tk.NORMAL)
            # 显示选择的图片
            self.display_image(self.image_path)
        else:
            self.path_var.set("")
            self.detect_btn.config(state=tk.DISABLED)
    
    def display_image(self, image_path):
        """在matplotlib中显示图片"""
        try:
            img = Image.open(image_path)
            # 增大图片预览尺寸以提高显示质量
            max_size = (600, 400)
            img.thumbnail(max_size)
            self.ax.clear()
            self.ax.imshow(img)
            self.ax.axis('off')
            self.ax.set_title(f"原图: {os.path.basename(image_path)}")
            self.canvas.draw()
        except Exception as e:
            messagebox.showerror("错误", f"无法加载图像: {e}")
    
    def start_detection(self):
        """开始检测图片"""
        if not self.image_path or not os.path.exists(self.image_path):
            messagebox.showerror("错误", "请选择有效的图片文件")
            return
        
        try:
            # 禁用按钮防止重复检测
            self.select_btn.config(state=tk.DISABLED)
            self.detect_btn.config(state=tk.DISABLED)
            self.judge_var.set("检测中...")
            self.root.update()
            
            # 执行检测
            img = Image.open(self.image_path)
            hot_pixels, dead_pixels = self.detector.detect_hot_dead_pixels(img)
            dirty_regions, dirty_percentage = self.detector.detect_lens_dirt(img)
            
            # 生成结果图像
            result_img = img.copy()
            draw = ImageDraw.Draw(result_img)
            
            # 标记热点（红色）
            for x, y in hot_pixels:
                draw.ellipse([(x-3, y-3), (x+3, y+3)], fill='red', outline='red', width=2)
            
            # 标记死点（蓝色）
            for x, y in dead_pixels:
                draw.ellipse([(x-3, y-3), (x+3, y+3)], fill='blue', outline='blue', width=2)
            
            # 标记脏污区域（黄色半透明区域）
            width, height = img.size
            dirt_mask = Image.new('RGBA', (width, height), (0, 0, 0, 0))
            dirt_draw = ImageDraw.Draw(dirt_mask)
            dirty_points = np.array(dirty_regions)
            
            if len(dirty_points) > 0:
                max_points = min(len(dirty_points), width * height // 100)  # 最多标记图像像素的1%
                sampled_points = dirty_points[:max_points]
                for x, y in sampled_points:
                    dirt_draw.ellipse([(x-2, y-2), (x+2, y+2)], fill=(255, 255, 0, 100))
            
            # 合并掩码
            result_img = Image.alpha_composite(result_img.convert('RGBA'), dirt_mask)
            self.result_img = result_img.convert('RGB')  # 保存结果图像
            
            # 显示结果图像
            self.ax.clear()
            self.ax.imshow(self.result_img)
            self.ax.axis('off')
            self.ax.set_title(f"检测结果: {os.path.basename(self.image_path)}")
            self.canvas.draw()
            
            # 更新结果表格
            self.update_result_table(hot_pixels, dead_pixels, dirty_percentage)
            
            # 判定结果
            self.judge_result(len(hot_pixels), len(dead_pixels), dirty_percentage)
            
            # 保存结果图像
            timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
            filename = os.path.basename(self.image_path)
            result_filename = f"{self.detector.result_dir}/{filename}_result_{timestamp}.jpg"
            self.result_img.save(result_filename)
            messagebox.showinfo("成功", f"检测完成，结果已保存至: {result_filename}")
            
        except Exception as e:
            messagebox.showerror("错误", f"检测过程中发生错误: {e}")
        finally:
            # 启用按钮
            self.select_btn.config(state=tk.NORMAL)
            self.detect_btn.config(state=tk.NORMAL)
    
    def update_result_table(self, hot_pixels, dead_pixels, dirty_percentage):
        """更新结果表格"""
        # 清空现有数据
        for item in self.result_tree.get_children():
            self.result_tree.delete(item)
        
        # 添加新数据
        self.result_tree.insert('', 'end', values=('图像路径', os.path.basename(self.image_path)))
        self.result_tree.insert('', 'end', values=('检测时间', datetime.now().strftime('%Y-%m-%d %H:%M:%S')))
        self.result_tree.insert('', 'end', values=('热点数量', len(hot_pixels)))
        self.result_tree.insert('', 'end', values=('死点数量', len(dead_pixels)))
        self.result_tree.insert('', 'end', values=('脏污百分比', f"{round(dirty_percentage * 100, 2)}%"))
    
    def judge_result(self, hot_count, dead_count, dirty_percentage):
        """判定检测结果是否通过"""
        # 根据用户需求：脏污比例低于10%，热点数量低于10个，死点数量低于1个判断通过
        dirty_ok = dirty_percentage * 100 < 10
        hot_ok = hot_count < 10
        dead_ok = dead_count < 1
        
        if dirty_ok and hot_ok and dead_ok:
            self.judge_var.set(f"检测结果: 通过\n\n脏污比例: {round(dirty_percentage * 100, 2)}% (< 10% 标准)\n热点数量: {hot_count} (< 1 标准)\n死点数量: {dead_count} (< 1 标准)")
            # 设置通过结果为绿色
            self.judge_label.config(foreground='green')
        else:
            reasons = []
            if not dirty_ok:
                reasons.append(f"脏污比例: {round(dirty_percentage * 100, 2)}% (≥ 10% 标准)")
            if not hot_ok:
                reasons.append(f"热点数量: {hot_count} (≥ 1 标准)")
            if not dead_ok:
                reasons.append(f"死点数量: {dead_count} (≥ 1 标准)")
            
            self.judge_var.set(f"检测结果: 未通过\n\n未通过原因:\n{'\n'.join(reasons)}")
            # 设置未通过结果为红色
            self.judge_label.config(foreground='red')

def main():
    # 确保中文显示正常
    plt.rcParams["font.family"] = ["SimHei", "WenQuanYi Micro Hei", "Heiti TC"]
    root = tk.Tk()
    app = PhotoDetectorGUI(root)
    root.mainloop()

if __name__ == '__main__':
    main()